type RGB = { r: number; g: number; b: number };

interface DitherImageOptions {
  url: string;
  type?: 'TYPE_A' | 'TYPE_B';
  palette?: string | null;
}

// 创建调色板函数
const createPalette = (palette: string): RGB[] => {
  const colors = palette.split('_');
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
  const res: RGB[] = [];

  colors.forEach((c: string) => {
    ctx.fillStyle = c;
    ctx.clearRect(0, 0, 1, 1);
    ctx.fillRect(0, 0, 1, 1);

    const imageData = ctx.getImageData(0, 0, 1, 1).data;
    res.push({ r: imageData[0], g: imageData[1], b: imageData[2] });
  });

  return res;
};

// 获取最接近的颜色
const getClosestColor = (currentColor: RGB, palette: string): RGB => {
  let colorPalette:RGB[] = []
  if (!palette) {
    colorPalette = [
      { r: 255, g: 255, b: 255 },
      { r: 0, g: 0, b: 0 },
    ];
  } else {
    colorPalette = createPalette(palette);
  }
  let closestColor: RGB = colorPalette[0];
  let minDistance = Number.MAX_VALUE;

  for (const color of colorPalette) {
    const distance = Math.sqrt(
      Math.pow(color.r - currentColor.r, 2) +
      Math.pow(color.g - currentColor.g, 2) +
      Math.pow(color.b - currentColor.b, 2)
    );

    if (distance < minDistance) {
      minDistance = distance;
      closestColor = color;
    }
  }

  return closestColor;
}

// 更新像素值
const refresh = (data: Uint8ClampedArray, i: number, dc: RGB): void => {
  data[i] += dc.r;
  data[i + 1] += dc.g;
  data[i + 2] += dc.b;
}

// 颜色减法
const sub = (c1: RGB, c2: RGB): RGB => {
  return {
    r: c1.r - c2.r,
    g: c1.g - c2.g,
    b: c1.b - c2.b,
  };
}

// 颜色乘法
const mul = (c: RGB, k: number): RGB =>{
  return {
    r: c.r * k,
    g: c.g * k,
    b: c.b * k,
  };
}

const  ditheringFilter= (imageData: ImageData): ImageData => {

  const { width: w, height: h, data } = imageData;

  for (let i = 0; i < data.length; i += 4) {
    const [r, g, b] = [data[i], data[i + 1], data[i + 2]];
    const c = getClosestColor({ r, g, b }, palette);

    [data[i], data[i + 1], data[i + 2]] = [c.r, c.g, c.b];

    const delta = sub({ r, g, b }, c);
    const x = (i / 4) % w;
    const y = Math.floor(i / 4 / w);

    if (x + 1 < w) refresh(data, i + 4, mul(delta, 7 / 16));
    if (x - 1 >= 0 && y + 1 < h) refresh(data, i + 4 * w - 4, mul(delta, 3 / 16));
    if (y + 1 < h) refresh(data, i + 4 * w, mul(delta, 5 / 16));
    if (x + 1 < w && y + 1 < h) refresh(data, i + 4 * w + 4, mul(delta, 1 / 16));
  }

  return imageData;
}

// Burke抖动算法
const ditheringBurke = (imageData: ImageData): ImageData =>{
  const { width, height, data } = imageData;
  const matrix = [
    [0, 0, 0, 8, 4],
    [2, 4, 8, 4, 2],
    [1, 2, 4, 2, 1],
  ];

  for (let y = 0; y < height; y++) {
    for (let x = 0; x < width; x++) {
      const index = (y * width + x) * 4;
      const [oldR, oldG, oldB] = [data[index], data[index + 1], data[index + 2]];
      const [newR, newG, newB] = [oldR > 127 ? 255 : 0, oldG > 127 ? 255 : 0, oldB > 127 ? 255 : 0];
      const [errR, errG, errB] = [oldR - newR, oldG - newG, oldB - newB];

      data[index] = newR;
      data[index + 1] = newG;
      data[index + 2] = newB;

      for (let i = 0; i < matrix.length; i++) {
        for (let j = 0; j < matrix[i].length; j++) {
          const offsetX = j - Math.floor(matrix[i].length / 2);
          const offsetY = i;
          const neighborX = x + offsetX;
          const neighborY = y + offsetY;

          if (neighborX >= 0 && neighborX < width && neighborY >= 0 && neighborY < height) {
            const neighborIndex = (neighborY * width + neighborX) * 4;
            data[neighborIndex] += (errR * matrix[i][j]) / 32;
            data[neighborIndex + 1] += (errG * matrix[i][j]) / 32;
            data[neighborIndex + 2] += (errB * matrix[i][j]) / 32;
          }
        }
      }
    }
  }

  return imageData;
}

const applyPalette = (imageData: ImageData, palette: string): ImageData => {
  const colorPalette = createPalette(palette);
  const data = imageData.data;

  for (let i = 0; i < data.length; i += 4) {
    const currentColor = { r: data[i], g: data[i + 1], b: data[i + 2] };
    const closestColor = getClosestColor(currentColor, colorPalette);
    data[i] = closestColor.r;
    data[i + 1] = closestColor.g;
    data[i + 2] = closestColor.b;
  }

  return imageData;
}

export async function ditherImageToBase64({ url, type = 'TYPE_A', palette = null }: DitherImageOptions): Promise<string | undefined> {
  if (!url) {
    return;
  }
  // 创建图片对象
  const image = new Image();
  image.src = url;
  image.crossOrigin = 'Anonymous'; // 设置跨域属性，允许加载其他域上的图片

  // 图片加载完成后执行
  image.onload = function () {
    // 创建一个Canvas元素
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
    canvas.willReadFrequently = true;
    // 设置Canvas的尺寸与图像相同
    canvas.width = image.width;
    canvas.height = image.height;

    // 在Canvas上绘制图像
    ctx.drawImage(image, 0, 0);

    // 获取Canvas中的图像数据
    const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);

    // 应用抖动滤镜
    const ditheredImageData = type === 'TYPE_A' ? ditheringBurke(imageData) : ditheringFilter(imageData);

    // 如果指定了调色板，则应用调色板
    const finalImageData = palette ? applyPalette(ditheredImageData, palette) : ditheredImageData;

    // 将修改后的图像数据绘制回Canvas上
    ctx.putImageData(finalImageData, 0, 0);

    // 将Canvas中的图像转换为base64编码
    const base64 = canvas.toDataURL('image/jpeg');

    // 将base64编码传递给resolve函数
    resolve(base64);
  };

  // 图片加载失败时执行
  image.onerror = function () {
    reject(new Error('Failed to load image'));
  };
}
